﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GA.Shared.Interfaces;
using System.Windows;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;
using System.Windows.Data;

namespace GA.Shared.Objects
{
    public class GameClass : LinkedDependencyObject
    {
        /// <summary>
        /// Identifies the Id Property.
        /// </summary>
        public static readonly DependencyProperty IdProperty =
            RegisterProperty(
                "Id",
                typeof(int),
                typeof(GameClass),
                new PropertyMetadata(-1));

        /// <summary>
        /// Identifies the GameClassTypeId Property.
        /// </summary>
        public static readonly DependencyProperty GameClassTypeIdProperty =
            RegisterProperty(
                "GameClassTypeId",
                typeof(int),
                typeof(GameClass),
                new PropertyMetadata(-1));

        /// <summary>
        /// Identifies the GameClassType Property.
        /// </summary>
        public static readonly DependencyProperty GameClassTypeProperty =
            RegisterProperty(
                "GameClassType",
                typeof(GameClassType),
                typeof(GameClass),
                new PropertyMetadata(null));

        /// <summary>
        /// Identifies the Xp Property.
        /// </summary>
        public static readonly DependencyProperty XpProperty =
            RegisterProperty(
                "Xp",
                typeof(int),
                typeof(GameClass),
                new PropertyMetadata(0, new PropertyChangedCallback(XpProperty_Changed)));

        /// <summary>
        /// Identifies the Level Property.
        /// </summary>
        public static readonly DependencyProperty LevelProperty =
            RegisterProperty(
                "Level",
                typeof(int),
                typeof(GameClass),
                new PropertyMetadata(0));

        /// <summary>
        /// Identifies the Levels Property.
        /// </summary>
        public static readonly DependencyProperty LevelsProperty =
            RegisterProperty(
                "Levels",
                typeof(ObservableCollection<KeyValuePair<int, GameClassLevel>>),
                typeof(GameClass),
                new PropertyMetadata(null));

        /// <summary>
        /// Gets a level based on Xp amount.
        /// </summary>
        /// <param name="xp">Xp amount to parse.</param>
        /// <returns>Level of the player.</returns>
        public static int GetLevel(int xp)
        {
            if (xp < 0) throw new ArgumentException("xp must be 0 or greater.");

            if (sXpLevels == null)
            {
                LoadLevels();
            }
            return sXpLevels.Last((xpLevel) => { return xpLevel.Value <= xp; }).Key;
        }

        /// <summary>
        /// Gets or sets the Id.
        /// </summary>
        
        public int Id
        {
            get { return (int)SafeGetValue(IdProperty); }
            set { SafeSetValue(IdProperty, value); }
        }

        /// <summary>
        /// Gets or sets the GameClassType Id.
        /// </summary>
        
        public int GameClassTypeId
        {
            get { return (int)SafeGetValue(GameClassTypeIdProperty); }
            set { SafeSetValue(GameClassTypeIdProperty, value); }
        }

        /// <summary>
        /// Gets or sets the GameClassType.
        /// </summary>
        
        public GameClassType GameClassType
        {
            get { return (GameClassType)SafeGetValue(GameClassTypeProperty); }
            set { SafeSetValue(GameClassTypeProperty, value); }
        }

        /// <summary>
        /// Gets or sets the Xp amount.
        /// </summary>
        
        public int Xp
        {
            get { return (int)SafeGetValue(XpProperty); }
            set { SafeSetValue(XpProperty, value); }
        }

        /// <summary>
        /// Gets or sets the Level.
        /// </summary>
        
        public int Level
        {
            get { return (int)SafeGetValue(LevelProperty); }
            set { SafeSetValue(LevelProperty, value); }
        }

        /// <summary>
        /// Gets or sets the Levels.
        /// </summary>
        
        public ObservableCollection<KeyValuePair<int, GameClassLevel>> Levels
        {
            get { return (ObservableCollection<KeyValuePair<int, GameClassLevel>>)SafeGetValue(LevelsProperty); }
            set { SafeSetValue(LevelsProperty, value); }
        }

        /// <summary>
        /// Gets the GameClassLevels.
        /// </summary>
        public IEnumerable<GameClassLevel> GameClassLevels
        {
            get
            {
                ObservableCollection<KeyValuePair<int, GameClassLevel>> collection = Levels;
                List<GameClassLevel> levels = new List<GameClassLevel>();
                foreach (KeyValuePair<int, GameClassLevel> level in collection)
                {
                    levels.Add(level.Value);
                }
                return levels;
            }
        }

        public GameClass()
        {
        }

        public GameClass(LinkedDependencyObject baseObject)
            : base(baseObject)
        {
        }

        public GameClass(LinkedDependencyObject baseObject, BindingMode bindingMode)
            : base(baseObject, bindingMode)
        {
        }

        private static Dictionary<int, int> sXpUpgrades = new Dictionary<int, int> { { 6, 2500 }, { 10, 4000 }, { 15, 4000 }, { 20, 4000 }, { 30, 8000 }, { 39, 8000 } };
        private static Dictionary<int, int> sXpLevels;
        private static int sMaxLevel = 50;

        private static void XpProperty_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ((GameClass)sender).SafeSetValue(LevelProperty, GetLevel((int)e.NewValue));
        }

        private static void LoadLevels()
        {
            sXpLevels = new Dictionary<int, int>();
            int lastXpRequired = 0;
            for (int level = 0; level <= sMaxLevel; level++)
            {
                int xpRequired = 0;
                List<KeyValuePair<int, int>> xpUpgrades = new List<KeyValuePair<int, int>>(sXpUpgrades.TakeWhile<KeyValuePair<int, int>>((xpUpgrade) => { return xpUpgrade.Key <= level; }));
                xpUpgrades.ForEach((xpUpgrade) => { xpRequired += xpUpgrade.Value; });
                sXpLevels.Add(level, xpRequired + lastXpRequired);
                lastXpRequired += xpRequired;
            }
        }


    }
}
